home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
3DDEMO.ZIP
/
3D
/
SOURCE
/
MESH.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-23
|
58KB
|
1,866 lines
#include "mesh.hpp"
// Copyright (c) 1996 by Kerrigan Burgess, all rights reserved.
int SHADING; // flag. which type? (Constant,Gouraud,Phong,Flat).
int TEXTUREMAPPED; // flag. Is it Texture Mapped?
int TRANSPARENCY; // flag. Is it enabled? (opaque/transparent).
int MORPHING; // flag. Is it enabled?
int SHADOWING; // flag. Are shadows enabled?
int HAZING; // flag. Is hazing on?
POLYGONCLASS **MeshList; // for final rendering.
int meshindex; // index for MeshList.
int shadowindex; // how many shadows per frame.
void ComputeAvgZ(void)
{
int count;
POLYGONCLASS *ThisPolygon;
for (count=shadowindex;count<meshindex;count++)
{
ThisPolygon = MeshList[count];
ThisPolygon->avgz=(float)0.33333*( (ThisPolygon->Vertex[0])->z +
(ThisPolygon->Vertex[1])->z +
(ThisPolygon->Vertex[2])->z );
}
}
int PolyCompare(const void *arg1, const void *arg2)
{
POLYGONCLASS *Poly1,*Poly2;
Poly1=*(POLYGONCLASS **)arg1;
Poly2=*(POLYGONCLASS **)arg2;
if (Poly1->avgz > Poly2->avgz)
return (-1);
else
if (Poly1->avgz < Poly2->avgz)
return (1);
else
return (0);
}
LIGHTCLASS::LIGHTCLASS(void) // Constructor.
{
lightsource.x=0; // light is at origin.
lightsource.y=0;
lightsource.z=0;
}
LIGHTCLASS::~LIGHTCLASS(void) // Destructor.
{
}
LIGHTCLASS::SetLight(float x, float y, float z)
{
// set light in world coords.
lightsource.x=x;
lightsource.y=y;
lightsource.z=z;
infinitelightsource.x=x;
infinitelightsource.y=y;
infinitelightsource.z=z*1000; // set it pretty dammed far.
}
POINT3D *LIGHTCLASS::GetLight(void)
{
return (&lightsource);
}
POINT3D *LIGHTCLASS::GetInfiniteLight(void)
{
return (&infinitelightsource);
}
CAMERACLASS::CAMERACLASS(void) // Constructor.
{
viewpoint.x=0;
viewpoint.y=0;
viewpoint.z=0;
angx=0;
angy=0;
angz=0;
}
CAMERACLASS::~CAMERACLASS(void) // Destructor.
{
}
void CAMERACLASS::SetViewPoint(float viewx, float viewy, float viewz)
{
viewpoint.x = viewx;
viewpoint.y = viewy;
viewpoint.z = viewz;
}
void CAMERACLASS::MoveViewPoint(float viewx, float viewy, float viewz)
{
viewpoint.x+=viewx;
viewpoint.y+=viewy;
viewpoint.z+=viewz;
}
POINT3D *CAMERACLASS::GetViewPoint(void)
{
return (&viewpoint);
}
void CAMERACLASS::SetViewAngle(int angle_x, int angle_y, int angle_z)
{
angx=angle_x;
angy=angle_y;
angz=angle_z;
}
void CAMERACLASS::MoveViewAngle(int angle_x, int angle_y, int angle_z)
{
angx+=angle_x;
angy+=angle_y;
angz+=angle_z;
}
void CAMERACLASS::CreateCameraMatrix(MATRIX CameraMatrix)
{
double Xa,Ya,Za;
float Sx,Cx,Sy,Cy,Sz,Cz;
// Change degree to radian
Xa = -angx*6.281/360;
Ya = -angy*6.281/360;
Za = -angz*6.281/360;
Sx = (float)sin ( Xa );
Cx = (float)cos ( Xa );
Sy = (float)sin ( Ya );
Cy = (float)cos ( Ya );
Sz = (float)sin ( Za );
Cz = (float)cos ( Za );
//T*Y*X*Z;
CameraMatrix[0][0] = Cy*Cz+Sy*Sx*Sz;
CameraMatrix[0][1] = -Cy*Sz+Sy*Sx*Cz;
CameraMatrix[0][2] = Sy*Cx;
CameraMatrix[0][3] = 0;
CameraMatrix[1][0] = Cx*Sz;
CameraMatrix[1][1] = Cx*Cz;
CameraMatrix[1][2] = -Sx;
CameraMatrix[1][3] = 0;
CameraMatrix[2][0] = -Sy*Cz+Cy*Sx*Sz;
CameraMatrix[2][1] = Sy*Sz+Cy*Sx*Cz;
CameraMatrix[2][2] = Cy*Cx;
CameraMatrix[2][3] = 0;
CameraMatrix[3][0] = -viewpoint.x*(Cy*Cz+Sy*Sx*Sz)
-viewpoint.y*(Cx*Sz)
-viewpoint.z*(-Sy*Cz+Cy*Sx*Sz);
CameraMatrix[3][1] = -viewpoint.x*(-Cy*Sz+Sy*Sx*Cz)
-viewpoint.y*(Cx*Cz)
-viewpoint.z*(Sy*Sz+Cy*Sx*Cz);
CameraMatrix[3][2] = -viewpoint.x*(Sy*Cx)
-viewpoint.y*(-Sx)
-viewpoint.z*(Cy*Cx);
CameraMatrix[3][3] = 1;
}
MESHCLASS::MESHCLASS(void) // constructor.
{
ObjectHead = NULL;
meshindex=0; // index for rendering list.
shadowindex=0; // how shadows in frame.
totalfaces=0;
MAX_LIGHTS = 1;
Light = new LIGHTCLASS [MAX_LIGHTS];
Light[0].SetLight(0,0,-1);
_CURRENTCAMERA_ = 0;
MAX_CAMERAS = 4;
Camera = new CAMERACLASS [MAX_CAMERAS];
int count;
for (count=0;count<MAX_CAMERAS;count++)
Camera[count] = CAMERACLASS(); // call constructor to initialize
velangx=0;
velangy=0;
velangz=0;
angx=0; // initialize rotation angles.
angy=0;
angz=0;
tx=ty=tz=0; // initialize translation vectors.
translevel=0; // start no transparency.
MORPHING=FALSE; // set morph to False.
SHADING = Gouraud; // default to Gouraud shading.
TEXTUREMAPPED = NoTexture; // default to no texture.
TRANSPARENCY = Opaque; // shut off transparency.
SHADOWING = NoShadow; // disable shadow mapping.
HAZING = NoHaze; // shut off hazing.
HITHER_Z = 10; // default Z clipping at these values.
YON_Z = 1000;
}
MESHCLASS::~MESHCLASS(void) // destructor.
{
if (Light != NULL)
delete Light;
if (Camera != NULL)
delete Camera;
if (ObjectHead != NULL)
delete ObjectHead;
if (MeshList != NULL)
delete MeshList;
}
void MESHCLASS::CreateMeshList(void)
{
if (MeshList != NULL)
delete MeshList;
MeshList = new POLYGONCLASS *[totalfaces]; // need to allocate for MeshList.
if (MeshList==NULL)
Error("Not enough memory\n");
}
void MESHCLASS::ResetOrigin(void) // put mesh back to 0,0,0 (world coords)
{
Camera[_CURRENTCAMERA_].SetViewAngle(0,0,0);
Camera[_CURRENTCAMERA_].SetViewPoint(0,0,0);
}
void MESHCLASS::SetMaxTransparency(int Levels)
{
MaxTransLevel = Levels;
}
void MESHCLASS::SetTransparencyLevel(int delta)
{
if (HAZING) // can't have both transparency and hazing.
return;
translevel+=delta;
TRANSPARENCY=Transparent;
if (translevel<0)
{
translevel=-1;
TRANSPARENCY=Opaque; // fully visible.
}
else
if (translevel>MaxTransLevel)
{
translevel=MaxTransLevel;
}
}
void MESHCLASS::SetShading(int Shade)
{
SHADING = Shade;
}
void MESHCLASS::SetTextureMapping(int mode)
{
TEXTUREMAPPED = mode;
}
void MESHCLASS::SetHazing(int mode)
{
HAZING = mode;
TRANSPARENCY=Opaque; // shut off.
}
void MESHCLASS::SetTransparency(int mode)
{
TRANSPARENCY=mode;
HAZING=NoHaze; // shut off.
}
void MESHCLASS::SetMorph(int mode)
{
MORPHING = mode;
}
void MESHCLASS::SetShadow(int Mode)
{
SHADOWING = Mode;
}
void MESHCLASS::SetTSRVectors(int angle_x, int angle_y, int angle_z,
int transx, int transy, int transz)
{
velangx+=angle_x; // change velocity of rotation angles.
velangy+=angle_y;
velangz+=angle_z;
tx=transx;
ty=transy;
tz=transz;
}
void MESHCLASS::ResetTSRVectors(void)
{
velangx=0;
velangy=0;
velangz=0;
angx=0;
angy=0;
angz=0;
tx=ty=tz=0;
}
void MESHCLASS::MoveCamera(int angle_x, int angle_y, int angle_z,
float viewx, float viewy, float viewz)
{
Camera[_CURRENTCAMERA_].MoveViewAngle(angle_x,angle_y,angle_z);
Camera[_CURRENTCAMERA_].MoveViewPoint(viewx,viewy,viewz);
}
void MESHCLASS::_3DPipeLine(void)
{
Camera[_CURRENTCAMERA_].CreateCameraMatrix(CameraMatrix);
CreateTSR_Matrix();
ObjectCull(CULL_XYZ);
DepthSort();
Render();
}
void MESHCLASS::Push(OBJECTCLASS *ThisObject,int Status)
{
switch (Status)
{
case PARENT:
if (ObjectHead == NULL) // first object.
{
ObjectHead = ThisObject;
ThisObject->morphsteps = 1/(float)100; // morph in 100 steps.
ThisObject->MorphSource = ThisObject; // reset Starting morph to Parent.
ThisObject->NextMorphObject = ThisObject; // point back to itself for circular list.
}
else
{
OBJECTCLASS *temp;
temp = ObjectHead;
while (temp->NextObject != NULL)
temp = temp->NextObject;
ThisObject->morphsteps = 1/(float)100; // morph in 100 steps.
ThisObject->MorphSource = ThisObject; // reset Starting morph to Parent.
ThisObject->NextMorphObject = ThisObject; // point back to itself for circular list.
temp->NextObject = ThisObject;
}
break;
case CHILD:
if (ObjectHead == NULL)
{
Error("Trying to initialize CHILD without PARENT\n");
}
else
{
OBJECTCLASS *temp, temp2;
temp = ObjectHead;
while (temp->NextObject != NULL)
temp = temp->NextObject;
ThisObject->NextMorphObject = temp->NextMorphObject; // point back to parent. Circular list.
temp->NextMorphObject = ThisObject;
}
break;
}
}
int MESHCLASS::SetWorldXYZ(int ObjectID,float wx,float wy,float wz)
{
OBJECTCLASS *temp;
temp=ObjectHead;
while ( (temp != NULL) && (temp->ObjectID != ObjectID) )
{
OBJECTCLASS *temp2;
temp2=temp->NextMorphObject;
while ( (temp2 != temp) && (temp2->ObjectID != ObjectID) ) // Search Children.
temp2=temp2->NextMorphObject;
if (temp2->ObjectID == ObjectID)
{
temp2->worldx = wx;
temp2->worldy = wy;
temp2->worldz = wz;
return (SUCCESS);
}
temp=temp->NextObject;
}
if (temp->ObjectID == ObjectID)
{
temp->worldx = wx;
temp->worldy = wy;
temp->worldz = wz;
return (SUCCESS);
}
else
return (FAILURE);
}
void MESHCLASS::SetCurrentCamera(int camera)
{
_CURRENTCAMERA_ = camera;
}
void MESHCLASS::ObjectCull(int Mode)
{
OBJECTCLASS *ThisObject;
float radius;
float xsphere,ysphere,zsphere,xcompare,ycompare;
ThisObject=ObjectHead; // point to head of list.
meshindex=0; // reset, for MeshList.
shadowindex=0; // reset how many shadows.
POINT3D *viewpoint, *lightsource, *infinitelightsource;
viewpoint=Camera[_CURRENTCAMERA_].GetViewPoint();
lightsource=Light[0].GetLight();
infinitelightsource=Light[0].GetInfiniteLight();
// if (MORPHING) // These 2 lines are only for the demo purposes because
// ThisObject=ThisObject->NextObject; // I only want the 2nd Parent object to morph not the first.
// Take these lines out for your own implementation and remove ( // ) from while statement and continues.
while ( ThisObject != NULL)
{
ThisObject=ThisObject->GetMorphObject(); // if morph enabled, return object else return root object.
ThisObject->Local2Camera(CameraMatrix, CENTER); // 1 means use world pos to transform.
ThisObject->GetCenterStats(&radius,&xsphere,&ysphere,&zsphere);
switch (Mode)
{
case CULL_Z:
if ( ((zsphere-radius) > YON_Z) ||
((zsphere+radius) < HITHER_Z) )
{
ThisObject=ThisObject->NextObject;
continue; // Not visible!
}
else
{
ThisObject->TransformObject(TSR_Matrix);
ThisObject->Local2Camera(CameraMatrix,VERTICES);
ThisObject->HSR_Shade(viewpoint,lightsource);
ThisObject->DoShadows(infinitelightsource);
ThisObject->PolyCull(Mode);
}
break;
case CULL_XYZ:
if ( ((zsphere-radius) > YON_Z) ||
((zsphere+radius) < HITHER_Z) )
{
ThisObject=ThisObject->NextObject;
continue;
}
xcompare = HALF_SCREEN_WIDTH_VD*zsphere;
if ( ((xsphere-radius) > xcompare) ||
((xsphere+radius) < -xcompare) )
{
ThisObject=ThisObject->NextObject;
continue;
}
ycompare = HALF_SCREEN_HEIGHT_VD*zsphere;
if ( ((xsphere-radius) > ycompare) ||
((xsphere+radius) < -ycompare) )
{
ThisObject=ThisObject->NextObject;
continue;
} // It passed all tests --> object is visible.
ThisObject->TransformObject(TSR_Matrix);
ThisObject->Local2Camera(CameraMatrix,VERTICES);
ThisObject->HSR_Shade(viewpoint,lightsource);
ThisObject->DoShadows(infinitelightsource);
ThisObject->PolyCull(Mode);
break;
default:
break;
} // end switch.
ThisObject=ThisObject->NextObject;
} // end while.
}
void MESHCLASS::CreateTSR_Matrix(void)
{
double Xa,Ya,Za;
float Sx,Cx,Sy,Cy,Sz,Cz;
angx+=velangx;
angy+=velangy;
angz+=velangz;
Xa = -angx*DEGREES_TO_RADIANS;
Ya = -angy*DEGREES_TO_RADIANS;
Za = -angz*DEGREES_TO_RADIANS;
Sx = (float)sin ( Xa );
Cx = (float)cos ( Xa );
Sy = (float)sin ( Ya );
Cy = (float)cos ( Ya );
Sz = (float)sin ( Za );
Cz = (float)cos ( Za );
TSR_Matrix[0][0] = Cy*Cz;
TSR_Matrix[0][1] = Cy*Sz;
TSR_Matrix[0][2] = -Sy;
TSR_Matrix[0][3] = 0;
TSR_Matrix[1][0] = Sx*Sy*Cz-Cx*Sz;
TSR_Matrix[1][1] = Sx*Sy*Sz+Cx*Cz;
TSR_Matrix[1][2] = Sx*Cy;
TSR_Matrix[1][3] = 0;
TSR_Matrix[2][0] = Cx*Sy*Cz+Sx*Sz;
TSR_Matrix[2][1] = Cx*Sy*Sz-Sx*Cz;
TSR_Matrix[2][2] = Cx*Cy;
TSR_Matrix[2][3] = 0;
}
void MESHCLASS::DepthSort(void)
{
if (meshindex != 0)
{
ComputeAvgZ();
qsort( &(MeshList[shadowindex]), meshindex-shadowindex,
sizeof( POLYGONCLASS *), PolyCompare );
}
}
void MESHCLASS::Render(void)
{
int pindex;
int SHADOW;
float x0,y0,z0,x1,y1,z1,x2,y2,z2;
POLYGONCLASS *ThisPolygon;
for (pindex=0;pindex<meshindex;pindex++)
{
ThisPolygon = MeshList[pindex];
SHADOW = ThisPolygon->shadowvisible;
if (SHADOW)
{
x0 = (ThisPolygon->shadow[0]).x;
y0 = (ThisPolygon->shadow[0]).y;
z0 = (ThisPolygon->shadow[0]).z;
x1 = (ThisPolygon->shadow[1]).x;
y1 = (ThisPolygon->shadow[1]).y;
z1 = (ThisPolygon->shadow[1]).z;
x2 = (ThisPolygon->shadow[2]).x;
y2 = (ThisPolygon->shadow[2]).y;
z2 = (ThisPolygon->shadow[2]).z;
ThisPolygon->shadowvisible = NoShadow; // reset.
}
else
{
x0 = (ThisPolygon->Vertex[0])->x;
y0 = (ThisPolygon->Vertex[0])->y;
z0 = (ThisPolygon->Vertex[0])->z;
x1 = (ThisPolygon->Vertex[1])->x;
y1 = (ThisPolygon->Vertex[1])->y;
z1 = (ThisPolygon->Vertex[1])->z;
x2 = (ThisPolygon->Vertex[2])->x;
y2 = (ThisPolygon->Vertex[2])->y;
z2 = (ThisPolygon->Vertex[2])->z;
}
long ix1,iy1,ix2,iy2,ix3,iy3;
_X1 = ix1 = (long)(HALF_SCREEN_WIDTH + x0*VIEWDISTANCE/z0);
_Y1 = iy1 = (long)(HALF_SCREEN_HEIGHT - y0*VD_ASPECTRATIO/z0);
_X2 = ix2 = (long)(HALF_SCREEN_WIDTH + x1*VIEWDISTANCE/z1);
_Y2 = iy2 = (long)(HALF_SCREEN_HEIGHT - y1*VD_ASPECTRATIO/z1);
_X3 = ix3 = (long)(HALF_SCREEN_WIDTH + x2*VIEWDISTANCE/z2);
_Y3 = iy3 = (long)(HALF_SCREEN_HEIGHT - y2*VD_ASPECTRATIO/z2);
switch ( TEXTUREMAPPED | SHADING | TRANSPARENCY | SHADOW | HAZING )
{
case WireFrame:
_ColorIndex=ThisPolygon->color+SHADES;
Scan_Convert_Wire();
break;
case Constant:
_ColorIndex = ThisPolygon->color + (ThisPolygon->Vertex[0])->Intensity;
Scan_Convert_Lambert();
break;
case Lambert:
_ColorIndex = ThisPolygon->color + (ThisPolygon->Vertex[0])->Intensity;
Scan_Convert_Lambert();
break;
case Gouraud:
_I1 = (ThisPolygon->Vertex[0])->Intensity;
_I2 = (ThisPolygon->Vertex[1])->Intensity;
_I3 = (ThisPolygon->Vertex[2])->Intensity;
_ColorIndex = ThisPolygon->color;
Scan_Convert_Gouraud();
break;
case Phong:
_A1 = (ThisPolygon->Vertex[0])->Intensity;
_A2 = (ThisPolygon->Vertex[1])->Intensity;
_A3 = (ThisPolygon->Vertex[2])->Intensity;
_ColorIndex = ThisPolygon->color;
Scan_Convert_Phong();
break;
case WireFrame_Texture: // just call same function again.
_ColorIndex=ThisPolygon->color+SHADES;
Scan_Convert_Wire();
break;
case Constant_Texture:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_ColorIndex = SHADES;
Scan_Convert_TextureL();
break;
case Lambert_Texture:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_ColorIndex = (ThisPolygon->Vertex[0])->Intensity;
Scan_Convert_TextureL();
break;
case Gouraud_Texture:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_I1 = (ThisPolygon->Vertex[0])->Intensity;
_I2 = (ThisPolygon->Vertex[1])->Intensity;
_I3 = (ThisPolygon->Vertex[2])->Intensity;
Scan_Convert_TextureG();
break;
case Phong_Texture:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_A1 = (ThisPolygon->Vertex[0])->Intensity;
_A2 = (ThisPolygon->Vertex[1])->Intensity;
_A3 = (ThisPolygon->Vertex[2])->Intensity;
Scan_Convert_TextureP();
break;
case WireFrame_Trans:
_ColorIndex=ThisPolygon->color+SHADES;
Scan_Convert_Wire();
break;
case Constant_Trans:
_ColorIndex = ThisPolygon->color + (ThisPolygon->Vertex[0])->Intensity;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Lambert_Trans:
_ColorIndex = ThisPolygon->color + (ThisPolygon->Vertex[0])->Intensity;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Gouraud_Trans:
_I1 = (ThisPolygon->Vertex[0])->Intensity;
_I2 = (ThisPolygon->Vertex[1])->Intensity;
_I3 = (ThisPolygon->Vertex[2])->Intensity;
_ColorIndex = ThisPolygon->color;
_TransLevel = translevel;
Scan_Convert_GouraudT();
break;
case Phong_Trans:
_A1 = (ThisPolygon->Vertex[0])->Intensity;
_A2 = (ThisPolygon->Vertex[1])->Intensity;
_A3 = (ThisPolygon->Vertex[2])->Intensity;
_ColorIndex = ThisPolygon->color;
_TransLevel = translevel;
Scan_Convert_PhongT();
break;
case WireFrame_Texture_Trans:
_ColorIndex=ThisPolygon->color+SHADES;
Scan_Convert_Wire();
break;
case Constant_Texture_Trans:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_ColorIndex = SHADES;
_TransLevel = translevel;
Scan_Convert_TextureLT();
break;
case Lambert_Texture_Trans:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_ColorIndex = (ThisPolygon->Vertex[0])->Intensity;
_TransLevel = translevel;
Scan_Convert_TextureLT();
break;
case Gouraud_Texture_Trans:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_I1 = (ThisPolygon->Vertex[0])->Intensity;
_I2 = (ThisPolygon->Vertex[1])->Intensity;
_I3 = (ThisPolygon->Vertex[2])->Intensity;
_TransLevel = translevel;
Scan_Convert_TextureGT();
break;
case Phong_Texture_Trans:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_A1 = (ThisPolygon->Vertex[0])->Intensity;
_A2 = (ThisPolygon->Vertex[1])->Intensity;
_A3 = (ThisPolygon->Vertex[2])->Intensity;
_TransLevel = translevel;
Scan_Convert_TexturePT();
break;
case WireFrame_Shadow:
_ColorIndex=ThisPolygon->shadowcolor;
Scan_Convert_Wire();
break;
case Constant_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case Lambert_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case Gouraud_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case Phong_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case WireFrame_Texture_Shadow: // just call same function again.
_ColorIndex=ThisPolygon->shadowcolor;
Scan_Convert_Wire();
break;
case Constant_Texture_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case Lambert_Texture_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case Gouraud_Texture_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case Phong_Texture_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
Scan_Convert_Lambert();
break;
case WireFrame_Trans_Shadow:
_ColorIndex=ThisPolygon->shadowcolor;
Scan_Convert_Wire();
break;
case Constant_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Lambert_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Gouraud_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Phong_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case WireFrame_Texture_Trans_Shadow:
_ColorIndex=ThisPolygon->shadowcolor;
Scan_Convert_Wire();
break;
case Constant_Texture_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Lambert_Texture_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Gouraud_Texture_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case Phong_Texture_Trans_Shadow:
_ColorIndex = ThisPolygon->shadowcolor;
_TransLevel = translevel;
Scan_Convert_LambertT();
break;
case WireFrame_Haze:
_ColorIndex=ThisPolygon->color+SHADES;
Scan_Convert_Wire();
break;
case Constant_Haze:
_ColorIndex = ThisPolygon->color + (ThisPolygon->Vertex[0])->Intensity;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Lambert_Haze:
_ColorIndex = ThisPolygon->color + (ThisPolygon->Vertex[0])->Intensity;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Gouraud_Haze:
_Z1 = (long)z0;
_Z2 = (long)z1;
_Z3 = (long)z2;
_I1 = (ThisPolygon->Vertex[0])->Intensity;
_I2 = (ThisPolygon->Vertex[1])->Intensity;
_I3 = (ThisPolygon->Vertex[2])->Intensity;
_ColorIndex = ThisPolygon->color;
Scan_Convert_GouraudH();
break;
case Phong_Haze:
_Z1 = (long)z0;
_Z2 = (long)z1;
_Z3 = (long)z2;
_A1 = (ThisPolygon->Vertex[0])->Intensity;
_A2 = (ThisPolygon->Vertex[1])->Intensity;
_A3 = (ThisPolygon->Vertex[2])->Intensity;
_ColorIndex = ThisPolygon->color;
Scan_Convert_PhongH();
break;
case WireFrame_Texture_Haze:
_ColorIndex=ThisPolygon->color+SHADES;
Scan_Convert_Wire();
break;
case Constant_Texture_Haze:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_ColorIndex = SHADES;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_TextureLH();
break;
case Lambert_Texture_Haze:
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_ColorIndex = (ThisPolygon->Vertex[0])->Intensity;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_TextureLH();
break;
case Gouraud_Texture_Haze:
_Z1 = (long)z0;
_Z2 = (long)z1;
_Z3 = (long)z2;
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_I1 = (ThisPolygon->Vertex[0])->Intensity;
_I2 = (ThisPolygon->Vertex[1])->Intensity;
_I3 = (ThisPolygon->Vertex[2])->Intensity;
Scan_Convert_TextureGH();
break;
case Phong_Texture_Haze:
_Z1 = (long)z0;
_Z2 = (long)z1;
_Z3 = (long)z2;
_U1 = ThisPolygon->u0;
_V1 = ThisPolygon->v0;
_U2 = ThisPolygon->u1;
_V2 = ThisPolygon->v1;
_U3 = ThisPolygon->u2;
_V3 = ThisPolygon->v2;
_A1 = (ThisPolygon->Vertex[0])->Intensity;
_A2 = (ThisPolygon->Vertex[1])->Intensity;
_A3 = (ThisPolygon->Vertex[2])->Intensity;
Scan_Convert_TexturePH();
break;
case WireFrame_Shadow_Haze:
_ColorIndex=ThisPolygon->shadowcolor;
Scan_Convert_Wire();
break;
case Constant_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Lambert_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Gouraud_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Phong_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case WireFrame_Texture_Shadow_Haze:
_ColorIndex=ThisPolygon->shadowcolor;
Scan_Convert_Wire();
break;
case Constant_Texture_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Lambert_Texture_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Gouraud_Texture_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
case Phong_Texture_Shadow_Haze:
_ColorIndex = ThisPolygon->shadowcolor;
_AvgZ = (long)ThisPolygon->avgz;
Scan_Convert_LambertH();
break;
}
}
}
OBJECTCLASS::OBJECTCLASS(void) // Constructor.
{
NextObject = NULL;
}
OBJECTCLASS::~OBJECTCLASS(void) // Destructor.
{
}
OBJECTCLASS *OBJECTCLASS::CreateMorphData(void)
{
POINT3D *LCoordSource,*LCoordDest;
LCoordSource = MorphSource->LocalCoord;
LCoordDest = (MorphSource->NextMorphObject)->LocalCoord;
int start,end,count;
switch (SHADING)
{
case Gouraud:
start=0;
end=numvertices;
break;
case Phong:
start=0;
end=numvertices;
break;
default:
start=0;
end=numvertices/2; // don't need to morph avgnormals for these.
break;
}
for (count=start;count<end;count++)
{
LCoordSource[count].morphx = 0; // reset. how much to add to each vertices when morphing.
LCoordSource[count].morphy = 0;
LCoordSource[count].morphz = 0;
LCoordSource[count].morphdx = ( LCoordDest[count].x -
LCoordSource[count].x )
* morphsteps;
LCoordSource[count].morphdy = ( LCoordDest[count].y -
LCoordSource[count].y )
* morphsteps;
LCoordSource[count].morphdz = ( LCoordDest[count].z -
LCoordSource[count].z )
* morphsteps;
}
OBJECTCLASS *temp;
temp = MorphSource;
MorphSource = MorphSource->NextMorphObject; // move source to next object.
return (temp); // return present source object.
}
OBJECTCLASS *OBJECTCLASS::GetMorphObject(void)
{
static float morphcount = 1.0; // CreateMorphData first time through.
static OBJECTCLASS *morphObject = NULL;
if (MORPHING)
{
morphcount += morphsteps; // inc count
if (morphcount > 1.0) // reset.
{
morphObject=CreateMorphData();
morphcount = 0.0;
}
}
else
{
morphObject=this; // if Morphing not enabled, just return root object.
MorphSource=this; // reset MorphSource to root (just in case it changed when morphing).
}
return (morphObject);
}
void OBJECTCLASS::GetCenterStats(float *radius, float *xsphere, float *ysphere,
float *zsphere)
{
*radius=this->radius;
*xsphere=this->xsphere; // in camera coords.
*ysphere=this->ysphere;
*zsphere=this->zsphere;
}
void OBJECTCLASS::TransformObject(MATRIX TSR_Matrix)
{
float x,y,z;
int index,start,end;
switch (SHADING)
{
case Gouraud:
start=0;
end=numvertices;
break;
case Phong:
start=0;
end=numvertices;
break;
default:
start=0;
end=numvertices/2;
break;
}
POINT3D *LCoord,*CCoord;
switch (MORPHING)
{
case TRUE:
for (index=start;index<end;index++)
{
LCoord = &( LocalCoord[index] );
CCoord = &( CameraCoord[index] );
LCoord->morphx += LCoord->morphdx; // get closer to destination object.
LCoord->morphy += LCoord->morphdy;
LCoord->morphz += LCoord->morphdz;
x = LCoord->x + LCoord->morphx;
y = LCoord->y + LCoord->morphy;
z = LCoord->z + LCoord->morphz;
CCoord->x = x*TSR_Matrix[0][0]+
y*TSR_Matrix[1][0]+
z*TSR_Matrix[2][0];
CCoord->y = x*TSR_Matrix[0][1]+
y*TSR_Matrix[1][1]+
z*TSR_Matrix[2][1];
CCoord->z = x*TSR_Matrix[0][2]+
y*TSR_Matrix[1][2]+
z*TSR_Matrix[2][2];
CCoord->valid = FALSE; // this is used for Gouraud and Phong shading when morphing.
// reset valid flag. Because when morphing the avgnormal
// goes out of whack and needs to be renormalized.
}
break;
case FALSE:
for (index=start;index<end;index++)
{
LCoord = &( LocalCoord[index] );
CCoord = &( CameraCoord[index] );
x = LCoord->x; // don't mess with local coords.
y = LCoord->y;
z = LCoord->z;
CCoord->x = x*TSR_Matrix[0][0]+
y*TSR_Matrix[1][0]+
z*TSR_Matrix[2][0];
CCoord->y = x*TSR_Matrix[0][1]+
y*TSR_Matrix[1][1]+
z*TSR_Matrix[2][1];
CCoord->z = x*TSR_Matrix[0][2]+
y*TSR_Matrix[1][2]+
z*TSR_Matrix[2][2];
CCoord->valid = FALSE; // this is used for Gouraud shading when morphing. And for Phong shading.
// reset valid flag. Because when morphing the avgnormal
// goes out of whack and needs to be renormalized.
}
break;
}
}
void OBJECTCLASS::Local2Camera(MATRIX CameraMatrix, int Mode)
{
int index,start,end;
float x,y,z;
switch (Mode)
{
case CENTER: // just transform object center --> camera.
x=worldx;
y=worldy;
z=worldz;
xsphere = x*CameraMatrix[0][0]+
y*CameraMatrix[1][0]+
z*CameraMatrix[2][0]+
CameraMatrix[3][0];
ysphere = x*CameraMatrix[0][1]+
y*CameraMatrix[1][1]+
z*CameraMatrix[2][1]+
CameraMatrix[3][1];
zsphere = x*CameraMatrix[0][2]+
y*CameraMatrix[1][2]+
z*CameraMatrix[2][2]+
CameraMatrix[3][2];
break;
case VERTICES:
switch (SHADING)
{
case Gouraud:
start=0;
end=numvertices;
break;
case Phong:
start=0;
end=numvertices;
break;
default:
start=0;
end=numvertices/2;
break;
}
POINT3D *CCoord;
for (index=start;index<end;index++)
{
CCoord = &( CameraCoord[index] );
x = CCoord->x + worldx;
y = CCoord->y + worldy;
z = CCoord->z + worldz;
CCoord->x = x*CameraMatrix[0][0]+
y*CameraMatrix[1][0]+
z*CameraMatrix[2][0]+
CameraMatrix[3][0];
CCoord->y = x*CameraMatrix[0][1]+
y*CameraMatrix[1][1]+
z*CameraMatrix[2][1]+
CameraMatrix[3][1];
CCoord->z = x*CameraMatrix[0][2]+
y*CameraMatrix[1][2]+
z*CameraMatrix[2][2]+
CameraMatrix[3][2];
}
break;
} // end switch.
}
void OBJECTCLASS::HSR_Shade(POINT3D *viewpoint, POINT3D *lightsource)
{
POINT3D normal, avgnormal, sightvector, lightvector, u, v;
POINT3D **VertexId;
POLYGONCLASS *ThisPolygon;
int pindex, vindex, intensity;
float angle, highlight;
for (pindex=0;pindex<numpoly;pindex++)
{
ThisPolygon = &(Polygon[pindex]); // alias for ease of access.
VertexId = ThisPolygon->Vertex;
MakeVector(VertexId[0],viewpoint,&sightvector);
MakeVector(VertexId[0],VertexId[1],&u);
MakeVector(VertexId[0],VertexId[2],&v);
CrossProduct(&u,&v,&normal);
if (SHADOWING)
CopyPoint3D(&normal,&(ThisPolygon->Normal)); // save. Use later on if Shadows are enabled.
angle=DotProduct(&normal,&sightvector);
if (angle>0) // acute, visible!
{
ThisPolygon->visible = TRUE;
switch (SHADING)
{
case WireFrame: // no shading needed.
break;
case Constant: // midpoint is the actual color.
(VertexId[0])->Intensity = HALF_SHADES;
break;
case Lambert:
MakeVector(VertexId[0],lightsource,&lightvector);
Normalize(&lightvector);
angle=DotProduct(&normal,&lightvector);
if (angle>0) // light is hitting the polygon.
{
highlight = (SHADES*angle)*ThisPolygon->Normalength;
if ( (intensity = AMBIENT + highlight) > SHADES)
intensity = SHADES;
(VertexId[0])->Intensity = (int)intensity;
}
else
(VertexId[0])->Intensity = AMBIENT;
break;
case Gouraud:
for (vindex=0;vindex<3;vindex++) // cycle through each vertex in poly.
{
MakeVector(VertexId[vindex],lightsource,&lightvector);
Normalize(&lightvector);
MakeVector(VertexId[vindex],ThisPolygon->AvgNormal[vindex],&avgnormal);
if (MORPHING)
Normalize(&avgnormal); // because when interpolating, avgnormals goes out of whack.
angle=DotProduct(&avgnormal,&lightvector);
if (angle>0) // light is hitting the polygon.
{
if ( (intensity = AMBIENT + SHADES*angle) > SHADES)
intensity = SHADES;
(VertexId[vindex])->Intensity = (int)intensity;
}
else
(VertexId[vindex])->Intensity = AMBIENT;
}
break;
case Phong:
for (vindex=0;vindex<3;vindex++) // cycle through each vertex in poly.
{
MakeVector(VertexId[vindex],lightsource,&lightvector);
Normalize(&lightvector);
MakeVector(VertexId[vindex],ThisPolygon->AvgNormal[vindex],&avgnormal);
if (MORPHING)
Normalize(&avgnormal); // because when interpolating, avgnormals goes out of whack.
angle=DotProduct(&avgnormal,&lightvector);
if (angle>0) // light is hitting the polygon.
{
if (!(VertexId[vindex])->valid)
{
angle -= 0.00005; // This is a bit of a kludge. Acos only accepts values between -1 and 1.
// However the value sometime comes to 1.00000011920929. Really 1 but acos doesn't like it.
// I could fix this by having more percision in my other routines but what the hell?
angle = (float)acos( (double)angle )*RADIANS_TO_DEGREES; // get actual angle between light and normal vector!
(VertexId[vindex])->Intensity = (int)angle;
(VertexId[vindex])->valid = TRUE; // we already got angle for this avgnormal.
}
}
else
(VertexId[vindex])->Intensity = AMBIENTANGLE;
}
break;
} // end switch.
} // end if visible
else
ThisPolygon->visible = FALSE;
} // end for loop
}
void OBJECTCLASS::DoShadows(POINT3D *lightsource)
{
int vindex,pindex;
float angle,slope;
POINT3D lightvector, **VertexId;
POLYGONCLASS *ThisPolygon;
if (SHADOWING) // only do if enabled.
{
for(pindex=0;pindex<numpoly;pindex++)
{
ThisPolygon = &(Polygon[pindex]);
angle=DotProduct(&(ThisPolygon->Normal),lightsource);
if (angle>0) // visible! Do Shadows.
{
ThisPolygon->shadowvisible = Shadow;
VertexId = ThisPolygon->Vertex;
for(vindex=0;vindex<3;vindex++)
{
MakeVector( VertexId[vindex], lightsource, &lightvector);
Normalize(&lightvector);
slope = 600/lightvector.z; // set shadow 600 units away from object. (looks pretty nice that far.)
(ThisPolygon->shadow[vindex]).x = (VertexId[vindex])->x + slope*lightvector.x;
(ThisPolygon->shadow[vindex]).y = (VertexId[vindex])->y + slope*lightvector.y;
(ThisPolygon->shadow[vindex]).z = (VertexId[vindex])->z + 200; // to look good when doing perspective correction.
}
MeshList[meshindex] = ThisPolygon; // add to beginning of rendering list (drawn first).
meshindex++;
shadowindex++; // how many shadows in scene.
}
else
ThisPolygon->shadowvisible = NoShadow;
} // end for.
} // end if SHADOW.
}
void OBJECTCLASS::PolyCull(int Mode)
{
int index;
float x1,x2,x3,y1,y2,y3,z1,z2,z3;
float compare1,compare2,compare3;
POLYGONCLASS *ThisPolygon;
switch (Mode)
{
case CULL_Z:
for (index=0;index<this->numpoly;index++)
{
ThisPolygon = &(this->Polygon[index]);
if (ThisPolygon->visible)
{ // extract z component.
z1=(ThisPolygon->Vertex[0])->z;
z2=(ThisPolygon->Vertex[1])->z;
z3=(ThisPolygon->Vertex[2])->z;
if ( (z1>HITHER_Z || z2>HITHER_Z || z3>HITHER_Z) &&
(z1<YON_Z || z2<YON_Z || z3<YON_Z) )
{
MeshList[meshindex]=ThisPolygon; // it's visible, add
meshindex++; // to meshlist for rendering.
}
}
}
break;
case CULL_XYZ: // do full polygon culling to frustrum.
for (index=0;index<this->numpoly;index++)
{
ThisPolygon = &(this->Polygon[index]);
if (ThisPolygon->visible) // only do if visible.
{
x1=(ThisPolygon->Vertex[0])->x; // extract cameracoords for clipping.
x2=(ThisPolygon->Vertex[1])->x;
x3=(ThisPolygon->Vertex[2])->x;
y1=(ThisPolygon->Vertex[0])->y;
y2=(ThisPolygon->Vertex[1])->y;
y3=(ThisPolygon->Vertex[2])->y;
z1=(ThisPolygon->Vertex[0])->z;
z2=(ThisPolygon->Vertex[1])->z;
z3=(ThisPolygon->Vertex[2])->z;
if (!((z1>HITHER_Z || z2>HITHER_Z || z3>HITHER_Z) &&
(z1<YON_Z || z2<YON_Z || z3<YON_Z)))
{
// is clipped --> don't add to MeshList.
continue;
}
compare1=HALF_SCREEN_WIDTH_VD*z1;
compare2=HALF_SCREEN_WIDTH_VD*z2;
compare3=HALF_SCREEN_WIDTH_VD*z3;
if (!((x1>-compare1 || x2>-compare2 || x3>-compare3) &&
(x1<compare1 || x2<compare2 || x3<compare3)))
{
// is clipped --> don't add to MeshList.
continue;
}
compare1=HALF_SCREEN_HEIGHT_VD*z1;
compare2=HALF_SCREEN_HEIGHT_VD*z2;
compare3=HALF_SCREEN_HEIGHT_VD*z3;
if (!((y1>-compare1 || y2>-compare2 || y3>-compare3) &&
(y1<compare1 || y2<compare2 || y3<compare3)))
{
// is clipped --> don't add to MeshList.
continue;
}
MeshList[meshindex]=ThisPolygon; // visible, so add to List.
meshindex++;
} // end if visible.
} // end for loop.
break;
}
}
void OBJECTCLASS::PreComputeNormal(int vertex0, int vertex1, int vertex2, int index)
{
POINT3D u,v,normal;
POINT3D *Vertex;
Vertex=this->LocalCoord;
MakeVector(&(Vertex[vertex0]),&(Vertex[vertex1]),&u);
MakeVector(&(Vertex[vertex0]),&(Vertex[vertex2]),&v);
CrossProduct(&u,&v,&normal);
Normalize(&normal); // normalize it!
// get new normal point.
// and save in vertex list.
Vertex[index].x = Vertex[vertex0].x + normal.x;
Vertex[index].y = Vertex[vertex0].y + normal.y;
Vertex[index].z = Vertex[vertex0].z + normal.z;
}
void OBJECTCLASS::ComputeNormalength(int vertex0, int vertex1, int vertex2,
POLYGONCLASS *ThisPolygon)
{
POINT3D u,v,normal;
POINT3D *Vertex;
Vertex=this->LocalCoord;
MakeVector(&(Vertex[vertex0]),&(Vertex[vertex1]),&u);
MakeVector(&(Vertex[vertex0]),&(Vertex[vertex2]),&v);
CrossProduct(&u,&v,&normal);
ThisPolygon->Normalength = 1/Magnitude(&normal);
}
void OBJECTCLASS::PreComputeAvgNormal(struct tempstruct *polystats)
{
int vertex0, vertex1, vertex2, commvertex, count, pindex, avgindex;
int Found=FALSE;
float sum;
POINT3D u, v, normal, avgnormal;
avgindex=numvertices; // start of avgnormals.
POINT3D *LCoord;
LCoord = LocalCoord;
for(commvertex=0;commvertex<numvertices;commvertex++)
{
avgnormal.x=0; avgnormal.y=0; avgnormal.z=0; // reset.
count=0;
// look for polys that have a common vertex.
for(pindex=0;pindex<numpoly;pindex++)
{
vertex0=polystats[pindex].p0;
vertex1=polystats[pindex].p1;
vertex2=polystats[pindex].p2;
if (vertex0 == commvertex)
{
Found=TRUE;
MakeVector( &(LCoord[vertex0]), &(LCoord[vertex1]), &u );
MakeVector( &(LCoord[vertex0]), &(LCoord[vertex2]), &v );
CrossProduct(&u,&v,&normal);
Polygon[pindex].AvgNormal[0] = &(CameraCoord[avgindex]);
}
else
if (vertex1 == commvertex)
{
Found=TRUE;
MakeVector( &(LCoord[vertex1]), &(LCoord[vertex2]), &u );
MakeVector( &(LCoord[vertex1]), &(LCoord[vertex0]), &v );
CrossProduct(&u,&v,&normal);
Polygon[pindex].AvgNormal[1] = &(CameraCoord[avgindex]);
}
else
if (vertex2 == commvertex)
{
Found=TRUE;
MakeVector( &(LCoord[vertex2]), &(LCoord[vertex0]), &u );
MakeVector( &(LCoord[vertex2]), &(LCoord[vertex1]), &v );
CrossProduct(&u,&v,&normal);
Polygon[pindex].AvgNormal[2] = &(CameraCoord[avgindex]);
}
if (Found)
{
Found=FALSE;
count++;
avgnormal.x+=normal.x;
avgnormal.y+=normal.y;
avgnormal.z+=normal.z;
}
} // end for (pindex).
if (count > 0) // Weired. Some objects don't have all vertices used.
{
sum=1/(float)count;
avgnormal.x = avgnormal.x * sum;
avgnormal.y = avgnormal.y * sum;
avgnormal.z = avgnormal.z * sum;
Normalize(&avgnormal);
LCoord[avgindex].x = LCoord[commvertex].x + avgnormal.x;
LCoord[avgindex].y = LCoord[commvertex].y + avgnormal.y;
LCoord[avgindex].z = LCoord[commvertex].z + avgnormal.z;
}
avgindex++;
}
}
void OBJECTCLASS::ComputeRadius(void)
{
int index;
double x,y,z,radius, new_radius,scale;
radius = 0;
for (index=0;index<this->numvertices;index++)
{
x=(double)this->LocalCoord[index].x;
y=(double)this->LocalCoord[index].y;
z=(double)this->LocalCoord[index].z;
new_radius=(float)sqrt( x*x + y*y + z*z );
if (new_radius>radius)
{
radius=new_radius;
}
}
scale=100/radius; // scale it to a good amount.
for (index=0;index<this->numvertices;index++)
{
this->LocalCoord[index].x=this->LocalCoord[index].x*scale;
this->LocalCoord[index].y=this->LocalCoord[index].y*scale;
this->LocalCoord[index].z=this->LocalCoord[index].z*scale;
}
this->radius=radius*scale;
this->maxz=this->maxz*scale;
}
void OBJECTCLASS::FindCenter(void)
{
POINT3D *Vertex;
int count;
Vertex = this->LocalCoord;
float minx,miny,minz;
minx=Vertex[0].x;
miny=Vertex[0].y;
minz=Vertex[0].z;
for (count=1;count<this->numvertices;count++) // find min x,y,z;
{
if ( Vertex[count].x < minx )
minx=Vertex[count].x;
if ( Vertex[count].y < miny )
miny=Vertex[count].y;
if ( Vertex[count].z < minz )
minz=Vertex[count].z;
}
float maxx,maxy,maxz;
maxx=Vertex[0].x;
maxy=Vertex[0].y;
maxz=Vertex[0].z;
for (count=1;count<this->numvertices;count++) // find max x,y,z;
{
if ( Vertex[count].x > maxx )
maxx=Vertex[count].x;
if ( Vertex[count].y > maxy )
maxy=Vertex[count].y;
if ( Vertex[count].z > maxz)
maxz=Vertex[count].z;
}
float worldx,worldy,worldz;
worldx=(minx+maxx)/(float)2;
worldy=(miny+maxy)/(float)2;
worldz=(minz+maxz)/(float)2;
for (count=0;count<this->numvertices;count++) // adjust local so it
{ // will be centered around 0,0,0
Vertex[count].x-=worldx;
Vertex[count].y-=worldy;
Vertex[count].z-=worldz;
}
this->worldx=0;
this->worldy=0;
this->worldz=250;
this->maxz=maxz;
}
POLYGONCLASS::POLYGONCLASS(void) // Constructor.
{
}
POLYGONCLASS::~POLYGONCLASS(void) // Destructor.
{
}
void MakeVector(POINT3D *init, POINT3D *term, POINT3D *vector)
{
vector->x = term->x - init->x;
vector->y = term->y - init->y;
vector->z = term->z - init->z;
}
void CrossProduct(POINT3D *u, POINT3D *v, POINT3D *normal)
{
normal->x = u->y*v->z - u->z*v->y;
normal->y = -(u->x*v->z - u->z*v->x);
normal->z = u->x*v->y - u->y*v->x;
}
float Magnitude(POINT3D *vector)
{
double x,y,z;
x=(double)vector->x; y=(double)vector->y; z=(double)vector->z;
return( (float)sqrt( x*x+y*y+z*z) );
}
void Normalize(POINT3D *vector)
{
double x,y,z,length;
x=(double)vector->x; y=(double)vector->y; z=(double)vector->z;
length=(float)sqrt( x*x+y*y+z*z );
if (length == 0)
length = 1;
vector->x/=length; vector->y/=length; vector->z/=length;
}
float DotProduct(POINT3D *u, POINT3D *v)
{
return( u->x*v->x + u->y*v->y + u->z*v->z );
}
void CopyPoint3D(POINT3D *source, POINT3D *dest)
{
dest->x = source->x;
dest->y = source->y;
dest->z = source->z;
}
void BenchMark(int type)
{
_X1=100; // 25 pixels per polygon.
_Y1=100;
_X2=107;
_Y2=100;
_X3=100;
_Y3=105;
switch (type)
{
case Lambert:
_ColorIndex = 370;
Scan_Convert_Lambert();
break;
case Gouraud:
_ColorIndex=16128;
_I1=10;
_I2=50;
_I3=35;
Scan_Convert_Gouraud();
break;
case Phong:
Scan_Convert_Phong();
break;
case Lambert_Texture:
break;
case Gouraud_Texture:
break;
case Phong_Texture:
break;
default:
break;
}
}